package com.jm.web.tags.support;

import java.util.Hashtable;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TryCatchFinally;

import org.apache.log4j.Logger;

import com.jm.utils.ObjectHelper;
import com.jm.utils.StringHelper;
import com.jm.web.BaseMainPage;
import com.jm.web.BasePage;
import com.jm.web.builder.BaseBuilder;
import com.jm.web.form.support.FormItem;
import com.jm.web.tags.DPTag;
import com.jm.web.tags.DialogTag;
import com.jm.web.tags.ExportTag;
import com.jm.web.tags.FormTag;
import com.jm.web.tags.SPTag;
import com.jm.web.tags.TabTag;
import com.jm.web.tags.table.ColumnEditorTag;
import com.jm.web.tags.table.TableTag;

/**
 * @author yanjie
 * Nov 2, 2011 2:03:20 PM
 */
public abstract class BaseTag extends BodyTagSupport implements TryCatchFinally{
	private static final long serialVersionUID = -4128326904242294931L;
	private final Logger log = Logger.getLogger(getClass());
	private static final String TAG_ID = "id";
	
	protected String strId = "";
	protected boolean bExport = false;
	protected boolean bExtend = false;
	protected boolean bParentExport = false;
	protected Hashtable<String,Object> extAttrList = new Hashtable<String,Object>();
	protected BaseBuilder builder = null;
	protected long cur = 0;
	protected DataSourceTag dataSourceTag = null;
	
	
	protected int onStartTag() {
		if(this.getPage().isExport() && !this.isEp()){
			return SKIP_BODY;
		}
		return EVAL_BODY_INCLUDE;
	}
	
	protected void preStartTag(){}

	protected void postStartTag() {}
	
	@Override
	public final int doStartTag(){
		cur = System.currentTimeMillis();
//		System.out.println(this.getClass().getName()+"---------"+"strat");
		int returnVal = EVAL_BODY_INCLUDE;
		
		preStartTag();
		returnVal = onStartTag();
		postStartTag();
		
		prepareBuilder();
		if(builder != null){
//			JspWriter writer = new JspWriter();
//			builder.setWriter(writer);
			builder.RenderStart();
//			try {
//				this.pageContext.getOut().write(writer.toString());
//			} catch (Exception exception) {
//				this.log.error(exception.getMessage(), exception);
//			}
		}
		
		return returnVal;
	}
	
	public void onInitBody(){
		
	}
	
	@Override
	public void doInitBody(){
		onInitBody();
	}
	
	public int onAfterBody(){
		if(this.getBodyContent() != null){
			prepareBuilder();
			if(builder != null){
//				JspWriter writer = new JspWriter();
//				builder.setWriter(writer);
				builder.RenderBody();
//				try {
//					this.getBodyContent().getEnclosingWriter().print(writer.toString());
//				} catch (Exception exception) {
//					this.log.error(exception.getMessage(), exception);
//				}
			}
		}
		return SKIP_BODY;
	}
	
	@Override
	public int doAfterBody() throws JspException {
		return onAfterBody();
	}
	
	protected int onEndTag(){
		return EVAL_PAGE;
	}
	protected void preEndTag() {}

	protected void postEndTag(){this.release();}
	
	@Override
	public int doEndTag(){
		int returnVal = EVAL_PAGE;
			preEndTag();
			returnVal = onEndTag();
			
			prepareBuilder();
			if(builder != null){
//				JspWriter writer = new JspWriter();
//				builder.setWriter(writer);
				builder.RenderEnd();
//				try {
//					
//					this.pageContext.getOut().write(writer.toString());
//				} catch (Exception exception) {
//					this.log.error(exception.getMessage(), exception);
//				}
			}
			
			postEndTag();
//		System.out.println(this.getClass().getName()+"---------"+"end");
		if(this.getPage().isDebug())
			System.out.println(this.getPage().getPageName()+"--"+this.getClass().getName()+"--"+this.GetExtValue("caption")+"--"+this.GetExtValue("name")+"--"+(System.currentTimeMillis() - cur) / 1000.0);
		
		return returnVal;
	}
	
	public void prepareBuilder(){
		if(this.builder != null)
			return;
		
		String strObject = getBuilderName();
		if(!StringHelper.IsNullOrEmpty(strObject)){
			Object obj = ObjectHelper.Create(strObject);
			if(obj == null)
			{
				log.error(StringHelper.Format("建立自定义Builer[%1$s]失败",strObject));
			}
			
			if(obj instanceof BaseBuilder){
				builder = (BaseBuilder)obj;
				builder.setOut(this.getPageContext().getOut());
				builder.init(this);
			}
		}
	}
	
	public String getBuilderName()
	{
		return null;
	}
	
	/*
	* 判断是否存在指定键值
	 * @param strKey
	 * @return
	 */
	public boolean IsContainsKey(String strKey)
	{
		strKey = strKey.toUpperCase();
		if (extAttrList != null)
		{
			return extAttrList.containsKey(strKey);
		}
		return false;
	}
	
	/**
	 * @param strKey
	 * @return
	 */
	public Object GetExtValue(String strKey)
	{
		strKey = strKey.toUpperCase();
		if (extAttrList != null)
			if (extAttrList.containsKey(strKey))
			{
				return extAttrList.get(strKey);
			}
		return null;
	}
	
	/**
	 * @param strKey
	 * @param strDefault
	 * @return
	 */
	public String GetExtValue(String strKey, String strDefault)
	{
		strKey = strKey.toUpperCase();
		if (extAttrList != null)
			if (extAttrList.containsKey(strKey))
			{
				Object value = extAttrList.get(strKey);
				if(value instanceof Boolean){
					return String.valueOf(value);
				}
				return (String) extAttrList.get(strKey);
			}
		return strDefault;
	}

	/**
	 * @param strKey
	 * @param nDefault
	 * @return
	 */
	public int GetExtValue(String strKey, int nDefault)
	{
		try
		{
			Integer tempValue = new Integer(nDefault);
			return Integer.parseInt(GetExtValue(strKey, tempValue.toString()));
		}
		catch (Exception ex)
		{
			return nDefault;
		}
	}

	/**
	 * @param strKey
	 * @param nDefault
	 * @return
	 */
	public long GetExtValue(String strKey, long nDefault)
	{
		try
		{
			Long nTempValue = new Long(nDefault);
			return Long.parseLong(GetExtValue(strKey, nTempValue.toString()));
		}
		catch (Exception ex)
		{
			return nDefault;
		}

	}

	/**
	 * @param strKey
	 * @param bDefault
	 * @return
	 */
	public boolean GetExtValue(String strKey, boolean bDefault)
	{
		try
		{
			return Boolean.parseBoolean(GetExtValue(strKey, bDefault ? "True" : "False"));
		}
		catch (Exception ex)
		{
			return bDefault;
		}
	}

	/**
	 * 设置附加属性
	 * 
	 * @param strKey
	 * @param strValue
	 */
	public void SetExtValue(String strKey, String strValue)
	{
		if (extAttrList == null)
			extAttrList = new Hashtable();
		extAttrList.put(strKey.toUpperCase(), strValue);
	}
	
	/**
	 * 设置附加属性
	 * 
	 * @param strKey
	 * @param strValue
	 */
	public void SetExtValue(String strKey, Object object)
	{
		if (extAttrList == null )
			extAttrList = new Hashtable();
		if(object != null)
			extAttrList.put(strKey.toUpperCase(), object);
	}
	
	/**
	 * @return
	 *  返回属性集
	 */
	public Hashtable<String,Object> getExtAttrList(){
		return this.extAttrList;
	}
	
	/**
	 * 删除扩展属性
	 * @param strKey
	 */
	public void RemoveExtValue(String strKey)
	{
		if (extAttrList == null)
			return ;
		
		extAttrList.remove(strKey.toUpperCase());
	}
	
	public PageContext getPageContext(){
		return this.pageContext;
	}
	
	public BaseMainPage getPage(){
		return (BaseMainPage)this.pageContext.getRequest().getAttribute(BasePage.TAG_CURRENT_PAGE);
	}
	
	
	public void doCatch(Throwable arg) throws Throwable {
		arg.printStackTrace();
	}
	
	public void clear(){
		builder = null;
		this.cur = 0;
		this.strId = "";
		this.bExport = false;
		this.bExtend = false;
		this.bParentExport = false;
		this.dataSourceTag = null;
		if(extAttrList != null)
			extAttrList.clear();
	}
	
	public void doFinally() {
		clear();
	}
	
	public String getId() {
		return this.strId;
	}

	public void setId(String strId) {
		this.strId = strId;
		this.SetExtValue(TAG_ID, strId);
	}
	
	/**
	 * @param tag
	 * @return
	 * 0 沒找到 1 找到 extend 
	 */
	public int getExtendParentExport(BaseTag tag){
		if(tag == null)
			return 0;
		
		while(tag != null){
			if(tag.getExtend()){
				this.bParentExport = tag.getExport();
				return 1 ;
			}
			tag = (BaseTag)tag.getParent();
		}
		return 0;
	}
	
	public boolean getExport() {
		if(this.GetExtValue("export") == null && (
				this instanceof FormTag 
				|| this instanceof ExportTag
		)){
			return true;
		}
		return bExport;
	}
	
	/**
	 * @return
	 * isEp 解決命名衝突
	 */
	public boolean isEp() {
		if(getExtendParentExport((BaseTag)this.getParent()) == 1){
			return this.bParentExport;
		}
		return this.getExport();
	}

	public void setExport(boolean export) {
		this.bExport = export;
		this.SetExtValue("export",export);
	}

	public boolean getExtend() {
		if(this.GetExtValue("extend") == null && (
				this instanceof ExportTag
		)){
			return true;
		}
		
		return bExtend;
	}

	public void setExtend(boolean extend) {
		bExtend = extend;
		this.SetExtValue("extend",extend);
	}
	
	public void setExportConfig(String strExportConfig) {
		this.SetExtValue("exportconfig",strExportConfig);
	}
	
	
	/**
	 * @return
	 */
	public DataSourceTag getDataSourceTag(){
		if(this.dataSourceTag != null)return this.dataSourceTag;
		BaseTag parentTag = (BaseTag)this.getParent();
		while(parentTag != null){
			if(parentTag instanceof DataSourceTag){
				this.dataSourceTag = (DataSourceTag)parentTag;
				break;
			}
			parentTag = (BaseTag)parentTag.getParent();
		}
		return dataSourceTag;
	}
	
	/**
	 * @return
	 */
	public boolean isColumnEditor(){
		boolean bcolEditor = false;
		if(this.getParent() != null && this.getParent() instanceof ColumnEditorTag){
			bcolEditor = true;
		}
		return bcolEditor;
	}
	
	/**
	 * @return
	 */
	public boolean isTableTagParent(){
		boolean result = false;
		BaseTag parentTag = (BaseTag)this.getParent();
		while(parentTag != null){
			if(parentTag instanceof TableTag){
				result = true;
				break;
			}else if(parentTag instanceof TabTag){
				result = false;
				break;
			}
			parentTag = (BaseTag)parentTag.getParent();
		}
		return result;
	}
	
	/**
	 * @return
	 * 是不是在表单中
	 */
	public boolean isDSP(){
		boolean bdp = false ;
		Tag tag = this.getParent();
		while(tag != null){
			if(tag instanceof SPTag || tag instanceof DPTag){
				bdp = true;
				break;
			}
			tag = tag.getParent();
		}
		return bdp;
	}
	
	/**
	 * @return
	 * 是不是在对话框中
	 */
	public boolean isDialog(){
		boolean bDialog = false ;
		Tag tag = this.getParent();
		while(tag != null){
			if(tag instanceof DialogTag){
				bDialog = true;
				break;
			}
			tag = tag.getParent();
		}
		return bDialog;
	}
	
	public void prepareParams(FormItem item){
		
		for(String key : this.getExtAttrList().keySet())
		{
			Object object = this.getExtAttrList().get(key);
			if(object instanceof String){
				item.OnSetProperty(key, (String)object);
			}else if(object instanceof Integer){
				item.OnSetProperty(key, (String)object);
			}else if(object instanceof Double){
				item.OnSetProperty(key, (String)object);
			}else if(object instanceof Float){
				item.OnSetProperty(key, (String)object);
			}else{
				item.OnSetProperty(key, object);
			}
		}
	}
}
